package auction.client;

import java.io.IOException;
import java.net.Socket;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import org.apache.log4j.Logger;
import org.bouncycastle.util.encoders.Base64;
import auction.securechannel.Base64Channel;
import auction.securechannel.Channel;
import auction.securechannel.RSAChannel;
import auction.securechannel.TCPChannel;



//Listen to Input from Server
public class ReceiverThread extends Thread {

	public static Logger log = Logger.getLogger(ReceiverThread.class);

	private boolean shutdown = false;
	private Channel decoratedChannel;
	private Socket socket;
	private boolean block = false;

	public ReceiverThread(Socket socket) throws IOException {
		this.socket = socket;

		decoratedChannel = Client.getDeoratedChannel();
	}

	public void run() {
		String input;
		byte[] temp;
		try {
			//while receiving input from channel
			while ((temp = decoratedChannel.receive()) != null) {

				input = new String(temp,"utf-8");
				log.debug("im while - input:"+input);

				if (input.startsWith("!list")) {
					/* server answer to !list */	
					String cut = input.substring(5);
					//Check for HMAC
					if(cut.contains("#HMAC#")){
						String[] message = cut.split("#HMAC#");
						if (message.length>0){
							Client.printAuctionList(message[0]);
							if(!(this.verifyMessage(message[0], message[1]))){
							
								//send !list again because HMAC was not correct
								decoratedChannel.send("!list".getBytes());
								input = new String(decoratedChannel.receive(),"utf-8");
								cut = input.substring(5);
								if(cut.contains("#HMAC#")){
									cut =cut.substring(0,cut.indexOf("#HMAC#"));
								}
								Client.printAuctionList(cut);
							}
						}
					}
					else{
						Client.printAuctionList(cut);
					}
				} 
				else if (input.equals("!end"))
					Client.cleanUp(0);

				else if (input.startsWith("!ok")){
					String cut = input.substring(4);
					String[] message = cut.split(" ");
					String cc = message[0];
					//check ClientChallenge
					log.debug("ClientChallenge from 1st message: "+Client.getClientChallenge());
					log.debug("ClientChallenge from 2nd message: "+cc);
					if (cc.equals(Client.getClientChallenge()))
						log.debug("ClientChallenge from 1st and 2nd message are identical");

					Client.setServerChallenge(message[1]);
					Client.setSecretKey(message[2]);
					Client.setIvParameter(message[3]);

					Client.establishSecureChannel();//incl.sending message 3
					decoratedChannel = Client.getDeoratedChannel();

					Client.setLoggedIn(true);

					Client.sendSignedBids();

				}
				else if (input.startsWith("!logout")){
					String cut = input.substring(7);
					System.out.println(cut);
					log.debug("!logout - go back to RSAChannel");
					Client.setDeoratedChannel(new RSAChannel(new Base64Channel(new TCPChannel(socket))));
					decoratedChannel = Client.getDeoratedChannel();//get RSAChannel again

					Client.setLoggedIn(false);

				}
				//used to block input in confirmation loop
				else if(input.startsWith("!block")){
					this.block=true;
				}
				//set client input free again
				else if(input.startsWith("!rejected")||input.startsWith("!confirmed")){
					this.block=false;
					System.out.println(input);
				}
				else if (input.startsWith("!getClientList")) {
					/* server answer to !getClientList */	
					String cut = input.substring(14);

					Client.setClientList(cut);

				} 
				else{
					if(!Client.isRefresh()){
						System.out.println(input);	//regular server answer
					}
					else
						Client.setRefresh(false);
				}
			}


			//Server got unavailable
			Client.closeServersocket();



		} catch (IOException e) {
			if (!shutdown) {
				e.printStackTrace();
				cleanUp();
			}
			log.debug("catch im receiverthread");
		} catch (NoSuchAlgorithmException e) {
			log.debug("Error: "+e.getMessage());
		} catch (NoSuchPaddingException e) {
			log.debug("Error: "+e.getMessage());
		} 
	}

	public void cleanUp() {
		shutdown = true;
	}
	//check HMACs
	public boolean verifyMessage(String  receivedMessage, String receivedMac){
		byte[] receivedByte = Base64.decode(receivedMac);
		byte[] generatedhmac = createHMAC(receivedMessage);
		return MessageDigest.isEqual(generatedhmac,receivedByte);
	}
	//create HMAC
	private byte[] createHMAC(String plain){
		byte[]plainarray = plain.getBytes();
		Mac hMac;
		try {
			hMac = Mac.getInstance("HmacSHA256");
			hMac.init(Client.getKey());
			hMac.update(plainarray);
			return hMac.doFinal();

		} catch (NoSuchAlgorithmException e) {
			log.debug("Error: "+e.getMessage());
		} catch (InvalidKeyException e) {
			log.debug("Error: "+e.getMessage());
		}

		// MESSAGE is the message to sign in bytes

		return null;
	}
	public boolean getBlockstatus(){
		return block;
	}

}
